package com.exrobot.module.rbt.service.order;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.exrobot.framework.common.util.collection.CollectionUtils;
import com.exrobot.framework.common.util.date.LocalDateTimeUtils;
import com.exrobot.module.rbt.controller.admin.orderitem.vo.OrderItemPageReqVO;
import com.exrobot.module.rbt.controller.admin.orderitem.vo.OrderItemRespVO;
import com.exrobot.module.rbt.controller.admin.robottask.vo.RobotTaskSaveReqVO;
import com.exrobot.module.rbt.controller.app.vo.MealCodeVO;
import com.exrobot.module.rbt.controller.app.vo.MiniproMessageVO;
import com.exrobot.module.rbt.dal.dataobject.orderitem.OrderItemDO;
import com.exrobot.module.rbt.dal.dataobject.robottask.RobotTaskDO;
import com.exrobot.module.rbt.dal.mysql.orderitem.OrderItemMapper;
import com.exrobot.module.rbt.dal.redis.RbtRedisDAO;
import com.exrobot.module.rbt.enums.RbtOrderStatusEnum;
import com.exrobot.module.rbt.enums.RbtTaskStatusEnum;
import com.exrobot.module.rbt.enums.RbtTaskTypeEnum;
import com.exrobot.module.rbt.framework.util.CommonUtils;
import com.exrobot.module.rbt.service.mqtt.MqttMessageService;
import com.exrobot.module.rbt.service.robotScheduler.RobotFood;
import com.exrobot.module.rbt.service.robotinfo.RobotInfoService;
import com.exrobot.module.rbt.service.robottask.RobotTaskService;
import jakarta.validation.Valid;
import jodd.util.StringUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.exrobot.module.rbt.controller.admin.order.vo.*;
import com.exrobot.module.rbt.dal.dataobject.order.OrderDO;
import com.exrobot.framework.common.pojo.PageResult;
import com.exrobot.framework.common.pojo.PageParam;
import com.exrobot.framework.common.util.object.BeanUtils;

import com.exrobot.module.rbt.dal.mysql.order.OrderMapper;

import static com.exrobot.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.exrobot.module.rbt.enums.ErrorCodeConstants.*;

/**
 * 食堂信息 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderItemMapper orderItemMapper;

    @Resource
    private RbtRedisDAO rbtRedisDAO;

    @Resource
    private RobotInfoService robotInfoService;

    @Resource
    private MqttMessageService mqttMessageService;

    @Resource
    private RobotTaskService robotTaskService;

    @Override
    public void bindOrderMenu(List<OrderItemDO> saleFoodDOList) {
        if(saleFoodDOList == null || saleFoodDOList.isEmpty()) {
            return;
        }
        Map<Long,Long> inventory = saleFoodDOList.stream().collect(Collectors.groupingBy(OrderItemDO::getMenuSn,Collectors.counting()));
        Long canteenId = saleFoodDOList.get(0).getCanteenSn();
        OrderPageReqVO reqVO = new OrderPageReqVO();
        reqVO.setStatus(0);
        reqVO.setOrderType(1);
        reqVO.setCanteenSn(canteenId);
        reqVO.setCreateTime(LocalDateTimeUtils.getTodayRange());
        List<OrderDO> list = getOrderList(reqVO);
        if(list != null && !list.isEmpty()) {
            Collection<String> orderSns = list.stream().map(OrderDO::getOrderSn).collect(Collectors.toSet());
            OrderItemPageReqVO itemPageReqVO = new OrderItemPageReqVO();
            itemPageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
            itemPageReqVO.setOrderSns(orderSns);
            itemPageReqVO.setStatus(0);
            Map<String,List<OrderItemDO>> orderItemListMap = CollectionUtils.convertMultiMap(orderItemMapper.selectPage(itemPageReqVO).getList(),OrderItemDO::getOrderSn);
            for (OrderDO orderDO : list) {
                if(orderItemListMap.containsKey(orderDO.getOrderSn())){
                    continue;
                }
                Map<Long, Long> order = orderItemListMap.get(orderDO.getOrderSn()).stream().collect(Collectors.groupingBy(OrderItemDO::getMenuSn,Collectors.counting()));
                if (!checkInventory(inventory,order)) {
                    continue;
                }
            }
        }
    }
    /**
     * 处理订单：检查库存是否满足，满足则扣减库存并绑定产品
     *
     * @param orderId 订单ID
     * @param order 订单需求，键为产品ID，值为需要的数量
     * @return 如果处理成功（库存满足并完成扣减和绑定）返回true，否则返回false
     */
    public boolean processOrder(String orderId, Map<String, Integer> order) {
        // 检查订单是否已处理
//        if (orderBindings.containsKey(orderId)) {
//            System.out.println("订单 " + orderId + " 已处理，请勿重复提交");
//            return false;
//        }

        // 检查库存是否满足订单需求
//        if (!checkInventory(order)) {
//            System.out.println("订单 " + orderId + " 因库存不足无法处理");
//            return false;
//        }

        // 扣减库存
//        deductInventory(order);

        // 绑定订单与产品
//        orderBindings.put(orderId, new HashMap<>(order));

        System.out.println("订单 " + orderId + " 处理成功，已扣减库存并完成产品绑定");
        return true;
    }

    /**
     * 检查库存是否满足订单需求
     */
    private boolean checkInventory(Map<Long,Long> inventory,Map<Long, Long> order) {
        if (order == null || order.isEmpty()) {
            return true;
        }

        Set<Long> productIds = order.keySet();
        for (Long productId : productIds) {
            Long requiredQuantity = order.get(productId);
            Long stockQuantity = inventory.getOrDefault(productId, 0L);

            if (stockQuantity < requiredQuantity) {
                return false;
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderDO createOrder(OrderSaveReqVO createReqVO) {
        if (StringUtil.isBlank(createReqVO.getOrderSn())) {
            throw exception(RBT_ORDER_SN_NOT_EXISTS);
        }
        if (getOrderBySn(createReqVO.getOrderSn()) != null) {
            throw exception(RBT_ORDER_SN_EXISTS,createReqVO.getOrderSn());
        }
        // 插入
        OrderDO order = BeanUtils.toBean(createReqVO, OrderDO.class);
        if(order.getOrderTime() == null) {
            order.setOrderTime(LocalDateTime.now());
        }
        if(StringUtil.isBlank(order.getCheckCode())) {
            order.setCheckCode(rbtRedisDAO.generateMealCode());
        }
        orderMapper.insert(order);
        if(createReqVO.getItemDOList() != null && !createReqVO.getItemDOList().isEmpty()) {
            orderItemMapper.insertBatch(createReqVO.getItemDOList());
        }
        // 返回
        return order;
    }


    @Override
    public void insertBatchOrderItem(List<OrderItemDO> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        orderItemMapper.insertBatch(list);
    }

    @Override
    public void updateOrder(OrderSaveReqVO updateReqVO) {
        // 校验存在
        validateOrderExists(updateReqVO.getId());
        // 更新
        OrderDO updateObj = BeanUtils.toBean(updateReqVO, OrderDO.class);
        orderMapper.updateById(updateObj);
    }

    @Override
    public void updateOrderItemStatus(List<Long> itemIds,Integer oldStatus,Integer newStatus) {
        LambdaUpdateWrapper<OrderItemDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(OrderItemDO::getId, itemIds);
        updateWrapper.eq(OrderItemDO::getStatus,oldStatus);
        updateWrapper.set(OrderItemDO::getStatus,newStatus);
        orderItemMapper.update(null,updateWrapper);
    }

    @Override
    public void updateOrderItemTask(List<Long> itemIds,String taskNo,String robotSn,Integer status) {
        LambdaUpdateWrapper<OrderItemDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(OrderItemDO::getId, itemIds);
        updateWrapper.eq(OrderItemDO::getStatus,RbtOrderStatusEnum.WAIT.getVal());
        updateWrapper.set(OrderItemDO::getStatus,status);
        updateWrapper.set(OrderItemDO::getTaskNo,taskNo);
        updateWrapper.set(OrderItemDO::getRobotSn,robotSn);
        orderItemMapper.update(null,updateWrapper);
    }

    @Override
    public void updateOrderItemTaskBySn(String orderSn,String taskNo,String robotSn,Integer status) {
        LambdaUpdateWrapper<OrderItemDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(OrderItemDO::getOrderSn, orderSn);
        updateWrapper.eq(OrderItemDO::getStatus,RbtOrderStatusEnum.SALE.getVal());
        updateWrapper.set(OrderItemDO::getStatus,status);
        updateWrapper.set(OrderItemDO::getTaskNo,taskNo);
        updateWrapper.set(OrderItemDO::getRobotSn,robotSn);
        orderItemMapper.update(null,updateWrapper);
    }

    @Override
    public void deleteOrder(Long id) {
        // 校验存在
        validateOrderExists(id);
        // 删除
        orderMapper.deleteById(id);
    }

    @Override
    public void deleteOrderListByIds(List<Long> ids) {
        // 删除
        orderMapper.deleteByIds(ids);
    }


    private void validateOrderExists(Long id) {
        if (orderMapper.selectById(id) == null) {
            throw exception(RBT_DATA_NOT_EXISTS);
        }
    }

    @Override
    public OrderDO getOrder(Long id) {
        return orderMapper.selectById(id);
    }

    @Override
    public OrderDO getOrderBySn(String orderSn) {
        return orderMapper.selectOne(OrderDO::getOrderSn, orderSn);
    }

    @Override
    public List<OrderRespVO> getTodayOrderVOByRobotSn(String robotSn,String taskNo) {
        OrderItemPageReqVO itemPageReqVO = new OrderItemPageReqVO();
        itemPageReqVO.setRobotSn(robotSn);
        itemPageReqVO.setStatus(RbtOrderStatusEnum.TAKE.getVal());
        itemPageReqVO.setCreateTime(LocalDateTimeUtils.getTodayRange());
        Map<String, List<OrderItemDO>> itemMap = CollectionUtils.convertMultiMap(orderItemMapper.selectPage(itemPageReqVO).getList(),OrderItemDO::getOrderSn);
        if(itemMap == null || itemMap.isEmpty()) {
            return new ArrayList<>();
        }
        OrderPageReqVO pageReqVO = new OrderPageReqVO();
        pageReqVO.setOrderSns(itemMap.keySet());
        List<OrderDO> list = orderMapper.selectPage(pageReqVO).getList();
        List<OrderRespVO> respVOList = new ArrayList<>();
        for(OrderDO orderDO : list) {
            if(itemMap.containsKey(orderDO.getOrderSn())) {
                OrderRespVO respVO = BeanUtils.toBean(orderDO,OrderRespVO.class);
                respVO.setItems(BeanUtils.toBean(itemMap.get(orderDO.getOrderSn()), OrderItemRespVO.class));
                respVOList.add(respVO);
            }
        }
        return respVOList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderDO matchToDayOrderAndUpdate(String robotSn,List<OrderItemDO> itemDOS) {
        LocalDateTime[] todayRange = LocalDateTimeUtils.getTodayRange();
        LambdaQueryWrapper<OrderItemDO> queryWrapper = new LambdaQueryWrapper<OrderItemDO>();
        queryWrapper
                .eq(OrderItemDO::getCanteenSn,itemDOS.get(0).getCanteenSn())
                .between(OrderItemDO::getCreateTime,todayRange[0],todayRange[1])
                .in(OrderItemDO::getStatus,Arrays.asList(RbtOrderStatusEnum.WAIT.getVal(),RbtOrderStatusEnum.TAKE.getVal()));
        List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(queryWrapper);
        if(orderItemDOList == null || orderItemDOList.isEmpty()) {
            return null;
        }
        List<Long> menuIds = itemDOS.stream().map(OrderItemDO::getMenuSn).sorted().toList();
        Map<String,List<OrderItemDO>> orderItemMap = CollectionUtils.convertMultiMap(orderItemDOList,OrderItemDO::getOrderSn);
        for(Map.Entry<String, List<OrderItemDO>> entry : orderItemMap.entrySet()) {
            List<OrderItemDO> itemList = entry.getValue();
            if(itemList.size() != menuIds.size()) {
                continue;
            }
            List<Long> newMenuIds = itemList.stream().map(OrderItemDO::getMenuSn).sorted().toList();
            if(menuIds.equals(newMenuIds)) {
                String orderSn = entry.getKey();
                OrderDO orderDO = orderMapper.selectFirstOne(OrderDO::getOrderSn,orderSn);
                if(orderDO == null) {
                    continue;
                }
//                LambdaUpdateWrapper<OrderItemDO> updateWrapper = new LambdaUpdateWrapper<OrderItemDO>();
//                updateWrapper.eq(OrderItemDO::getOrderSn, orderSn)
//                        .in(OrderItemDO::getStatus, Arrays.asList(RbtOrderStatusEnum.WAIT.getVal(),RbtOrderStatusEnum.TAKE.getVal()))
//                        .set(OrderItemDO::getRobotSn, robotSn)
//                        .set(OrderItemDO::getStatus, RbtOrderStatusEnum.ORDER.getVal());
//                orderItemMapper.update(null, updateWrapper);
//                if(orderItemMapper.update(null, updateWrapper) > 0) {
//
//                }
                for (OrderItemDO itemDO : itemDOS) {
                    LambdaUpdateWrapper<OrderItemDO> updateItemWrapper = new LambdaUpdateWrapper<>();
                    updateItemWrapper.eq(OrderItemDO::getOrderSn, orderSn)
                            .in(OrderItemDO::getStatus, Arrays.asList(RbtOrderStatusEnum.WAIT.getVal(),RbtOrderStatusEnum.TAKE.getVal()))
                            .set(OrderItemDO::getRobotSn, robotSn)
                            .set(OrderItemDO::getRobotBoxSn,itemDO.getRobotBoxSn())
                            .set(OrderItemDO::getStatus, RbtOrderStatusEnum.ORDER.getVal())
                            .last("LIMIT 1");;
                    orderItemMapper.update(null, updateItemWrapper);
                }
                return orderDO;
            }
        }
        return null;
    }

    @Override
    public PageResult<OrderDO> getOrderPage(OrderPageReqVO pageReqVO) {
        return orderMapper.selectPage(pageReqVO);
    }

    @Override
    public List<OrderDO> getOrderList(OrderPageReqVO pageReqVO) {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        return orderMapper.selectPage(pageReqVO).getList();
    }

    /**
     * 更新订单完成
     * */
    @Override
    public OrderDO updateOrderCompleted(String robotSn,String code) {
        LocalDateTime[] dateTime = LocalDateTimeUtils.getTodayRange();
        LambdaQueryWrapper<OrderDO> queryWrapper = new LambdaQueryWrapper<OrderDO>();
        queryWrapper.eq(OrderDO::getCheckCode,code);
        queryWrapper.between(OrderDO::getCreateTime,dateTime[0],dateTime[1]);
        OrderDO orderDO = orderMapper.selectOne(queryWrapper);
        if(orderDO == null) {
            return null;
        }
        // 更新
        LambdaUpdateWrapper<OrderItemDO> updateWrapper = new LambdaUpdateWrapper<OrderItemDO>();
        updateWrapper.eq(OrderItemDO::getRobotSn, robotSn)
                .eq(OrderItemDO::getOrderSn, orderDO.getOrderSn())
                .eq(OrderItemDO::getStatus, RbtOrderStatusEnum.ORDER.getVal())
                .set(OrderItemDO::getStatus, RbtOrderStatusEnum.COMPLETED.getVal());
        orderItemMapper.update(null, updateWrapper);
        return orderDO;
    }

    @Override
    public void updateOrderChange(String sn,List<String> codes) {
        LocalDateTime[] todayRange = LocalDateTimeUtils.getTodayRange();
        Collection<String> orderSns = new ArrayList<>();
        if (codes != null && !codes.isEmpty()) {
            LambdaQueryWrapper<OrderDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(OrderDO::getCheckCode, codes);
            queryWrapper.between(OrderDO::getOrderTime, todayRange[0], todayRange[1]);
            List<OrderDO> orderList = orderMapper.selectList(queryWrapper);
            if (orderList != null && !orderList.isEmpty()) {
                orderSns = orderList.stream().map(OrderDO::getOrderSn).collect(Collectors.toSet());
            }
        } else {
            LambdaQueryWrapper<OrderItemDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(OrderItemDO::getRobotBoxSn, sn);
            queryWrapper.between(OrderItemDO::getCreateTime, todayRange[0], todayRange[1]);
            queryWrapper.eq(OrderItemDO::getStatus, RbtOrderStatusEnum.ORDER.getVal());
            List<OrderItemDO> orderItemList = orderItemMapper.selectList(queryWrapper);
            if (orderItemList != null && !orderItemList.isEmpty()) {
                orderSns = orderItemList.stream().map(OrderItemDO::getOrderSn).collect(Collectors.toSet());
            }
        }
        if (orderSns.isEmpty()) {
            return;
        }
        LambdaUpdateWrapper<OrderDO> updateOrderWrapper = new LambdaUpdateWrapper<>();
        updateOrderWrapper.in(OrderDO::getOrderSn, orderSns)
                .set(OrderDO::getPoint, "")
                .set(OrderDO::getStatus, RbtOrderStatusEnum.SALE.getVal());
        orderMapper.update(null, updateOrderWrapper);
        LambdaUpdateWrapper<OrderItemDO> updateOrderItemWrapper = new LambdaUpdateWrapper<>();
        updateOrderItemWrapper.in(OrderItemDO::getRobotSn, orderSns)
                .between(OrderItemDO::getCreateTime, todayRange[0], todayRange[1])
                .eq(OrderItemDO::getStatus, RbtOrderStatusEnum.ORDER.getVal())
                .set(OrderItemDO::getRobotBoxSn, "")
                .set(OrderItemDO::getStatus, RbtOrderStatusEnum.SALE.getVal());
        orderItemMapper.update(null, updateOrderItemWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderDO updateOrderBindRobotbox(OrderSaveReqVO reqVO) {
        OrderDO orderDO = null;
        if(StringUtil.isBlank(reqVO.getOrderSn())) {
            orderDO = matchToDayOrderAndUpdate(reqVO.getItemDOList().get(0).getRobotSn(),reqVO.getItemDOList());
        } else {
            orderDO = this.getOrderBySn(reqVO.getOrderSn());
        }
        if(orderDO == null) {
            return orderDO;
        }
        for (OrderItemDO itemDO : reqVO.getItemDOList()) {
            LambdaUpdateWrapper<OrderItemDO> updateItemWrapper = new LambdaUpdateWrapper<>();
            updateItemWrapper.eq(OrderItemDO::getOrderSn, reqVO.getOrderSn())
                    .in(OrderItemDO::getStatus, Arrays.asList(RbtOrderStatusEnum.WAIT.getVal(),RbtOrderStatusEnum.TAKE.getVal()))
                    .eq(OrderItemDO::getCanteenSn, itemDO.getCanteenSn())
                    .eq(OrderItemDO::getMenuSn, itemDO.getMenuSn())
                    .set(OrderItemDO::getRobotSn, itemDO.getRobotSn())
                    .set(OrderItemDO::getRobotBoxSn,itemDO.getRobotBoxSn())
                    .last("LIMIT 1");;
            orderItemMapper.update(null, updateItemWrapper);
        }
        return orderDO;
    }

    @Override
    public List<RobotFood> getRobotSalseFoodByToday() {
        List<RobotFood> robotFoodList = new ArrayList<>();
        List<OrderItemDO> list = getSalseFoodByToday(null);
        if(list == null || list.isEmpty()) {
            return robotFoodList;
        }
        Map<String,List<OrderItemDO>> getRobotMap = list.stream().collect(Collectors.groupingBy(OrderItemDO::getRobotSn));
        for (Map.Entry<String, List<OrderItemDO>> item : getRobotMap.entrySet()) {
            String sn = item.getKey();
            String floor = CommonUtils.getFloorByPoint(rbtRedisDAO.getPoint(sn));
            if(StringUtil.isBlank(floor)) {
                continue;
            }
            List<OrderItemDO> orderItemList = item.getValue();
            Map<Long, Integer> foodMap = orderItemList.stream().collect(Collectors.groupingBy(
                    OrderItemDO::getMenuSn, // 分组键：商品ID
                    Collectors.collectingAndThen(Collectors.counting(), Long::intValue)
                   ));
            robotFoodList.add(new RobotFood(sn, floor, foodMap));
        }
        return robotFoodList;
    }

    private List<OrderItemDO> getSalseFoodByToday(List<String> sns) {

        LocalDateTime[] todayRange = LocalDateTimeUtils.getTodayRange();
        LambdaQueryWrapper<OrderItemDO> queryWrapper = new LambdaQueryWrapper<OrderItemDO>();
        queryWrapper.between(OrderItemDO::getCreateTime,todayRange[0],todayRange[1])
                .eq(OrderItemDO::getStatus, RbtOrderStatusEnum.SALE.getVal());
        if(sns != null && !sns.isEmpty()) {
            queryWrapper.in(OrderItemDO::getRobotSn,sns);
        }
        return orderItemMapper.selectList(queryWrapper);
    }

    @Override
    public List<OrderItemDO> getOrderItemList(OrderItemPageReqVO reqVO) {
        reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        return orderItemMapper.selectPage(reqVO).getList();
    }

}